/** 
 *
 * Lisense:
 * Copyright (c) 2015.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @fileDesc:TODO
 * @author:dairymix
 * @version:1.0.0
 */
package com.serv.config.datasource.other;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.explorer.ui.login.DefaultLoginHandler;
import org.activiti.explorer.ui.login.LoginHandler;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.activiti.spring.SpringAsyncExecutor;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.AbstractProcessEngineAutoConfiguration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidAbstractDataSource;
import com.alibaba.druid.pool.DruidDataSource;
import com.google.common.collect.Maps;

/** 
 * @ClassName:ActivitiDataSourceConfig
 * @Description:TODO
 * @author:dairymix
 * @version:1.0.0
 */
@Configuration
@ConfigurationProperties(prefix = "datasource.activiti",locations = "classpath:ds/datasource.yml")
@MapperScan(basePackages = ActivitiDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "activitiSqlSessionFactory")
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "apEntityManagerFactory", 
    transactionManagerRef = "apTransactionManager", 
    basePackages = { ActivitiDataSourceConfig.PACKAGE+".repo" })
//public class ActivitiDataSourceConfig {
public class ActivitiDataSourceConfig extends AbstractProcessEngineAutoConfiguration{

//    @Autowired
//    private static Environment env;

    static final String PACKAGE = "com.serv.model.activiti";
    
    //@Value("${spring.datasource_boot.url}")
    private String url;
    //@Value("${spring.datasource_boot.username}")
    private String username;
    //@Value("${spring.datasource_boot.password}")
    private String password;
    //@Value("${spring.datasource_boot.driverClassName}")
    private String driverClassName;
    
    private String type;

    private Map<String, String> druid  = Maps.newHashMap();
//    private String maxActive;
//    private String initialSize;
//    private String minIdle;
//    private String maxWait;
//    private String timeBetweenEvictionRunsMillis;
//    private String minEvictableIdleTimeMillis;
//    private String testWhileIdle;
//    private String testOnBorrow;
//    private String testOnReturn;
//    private String poolPreparedStatements;

    /*********************************************/
    
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Map<String, String> getDruid() {
        return druid;
    }

    public void setDruid(Map<String, String> druid) {
        this.druid = druid;
    }

    public String getMaxActive() {
        return this.druid.get("maxActive");
    }

    public void setMaxActive(String maxActive) {
        this.druid.put("maxActive", maxActive);
    }

    public String getInitialSize() {
        return this.druid.get("initialSize");
    }

    public void setInitialSize(String initialSize) {
        this.druid.put("initialSize", initialSize);
    }

    public String getMinIdle() {
        return this.druid.get("minIdle");
    }

    public void setMinIdle(String minIdle) {
        this.druid.put("minIdle", minIdle);
    }

    public String getMaxWait() {
        return this.druid.get("maxWait");
    }

    public void setMaxWait(String maxWait) {
        this.druid.put("maxWait", maxWait);
    }

    public String getTimeBetweenEvictionRunsMillis() {
        return this.druid.get("timeBetweenEvictionRunsMillis");
    }

    public void setTimeBetweenEvictionRunsMillis(
            String timeBetweenEvictionRunsMillis) {
        this.druid.put("timeBetweenEvictionRunsMillis", timeBetweenEvictionRunsMillis);
    }

    public String getMinEvictableIdleTimeMillis() {
        return this.druid.get("minEvictableIdleTimeMillis");
    }

    public void setMinEvictableIdleTimeMillis(String minEvictableIdleTimeMillis) {
        this.druid.put("minEvictableIdleTimeMillis", minEvictableIdleTimeMillis);
    }

    public String getTestWhileIdle() {
        return this.druid.get("testWhileIdle");
    }

    public void setTestWhileIdle(String testWhileIdle) {
        this.druid.put("testWhileIdle", testWhileIdle);
    }

    public String getTestOnBorrow() {
        return this.druid.get("testOnBorrow");
    }

    public void setTestOnBorrow(String testOnBorrow) {
        this.druid.put("testOnBorrow", testOnBorrow);
    }

    public String getTestOnReturn() {
        return this.druid.get("testOnReturn");
    }

    public void setTestOnReturn(String testOnReturn) {
        this.druid.put("testOnReturn", testOnReturn);
    }

    public String getPoolPreparedStatements() {
        return this.druid.get("poolPreparedStatements");
    }

    public void setPoolPreparedStatements(String poolPreparedStatements) {
        this.druid.put("poolPreparedStatements", poolPreparedStatements);
    }

    /*********************************************/

    @Bean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(
            PlatformTransactionManager transactionManager,
            SpringAsyncExecutor springAsyncExecutor) throws IOException {
        SpringProcessEngineConfiguration processEngineConfiguration = 
                baseSpringProcessEngineConfiguration(activitiDataSource(),
                        transactionManager, springAsyncExecutor);
        processEngineConfiguration
            .setProcessEngineName(ProcessEngines.NAME_DEFAULT)
            .setDatabaseSchemaUpdate("true")
            .setJobExecutorActivate(false)
            .setActivityFontName("宋体")
            .setLabelFontName("宋体");
        return processEngineConfiguration; 
//        return baseSpringProcessEngineConfiguration(activitiDataSource(),
//                transactionManager, springAsyncExecutor);
    }

    @Bean(name="activitiLoginHandler")
    public LoginHandler getActivitiLoginHandler(ProcessEngine processEngine) {
        DefaultLoginHandler loginHandler = new DefaultLoginHandler();
        loginHandler.setIdentityService(processEngine.getIdentityService());
        return loginHandler;
    }

    //filepath="d:\\Download\\process.png"
    //生成流程图的时候设置字体和编码信息解决，如下
    //这个需要放到activiti的相关model中,暂时放置在这里
    //processEngine可以由SpringProcessEngineConfiguration构造
    public void genPic(ProcessEngine processEngine,String procId,String filePath) throws Exception {
        ProcessInstance pi = processEngine.getRuntimeService()
                .createProcessInstanceQuery().processInstanceId(procId)
                .singleResult();
        BpmnModel bpmnModel = processEngine.getRepositoryService()
                .getBpmnModel(pi.getProcessDefinitionId());
        List<String> activeIds = processEngine.getRuntimeService()
                .getActiveActivityIds(pi.getId());
        ProcessDiagramGenerator p = new DefaultProcessDiagramGenerator();
        InputStream is = p.generateDiagram(bpmnModel, "png", activeIds,
                Collections.<String> emptyList(), "宋体", "宋体", "宋体", null, 1.0);

        File file = new File(filePath);
        OutputStream os = new FileOutputStream(file);

        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }

        os.close();
        is.close();
    }

    @Bean(name = "activitiDataSource")
    public DataSource activitiDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(getDriverClassName());
        dataSource.setUrl(getUrl());
        dataSource.setUsername(getUsername());
        dataSource.setPassword(getPassword());
        try {
            druidAttribute(dataSource);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

    public DataSource druidAttribute(DataSource dataSource) throws SQLException {
        DruidAbstractDataSource ds = (DruidAbstractDataSource) dataSource;
        ds.setInitialSize(Integer.valueOf(getInitialSize()));
        ds.setMinIdle(Integer.valueOf(getMinIdle()));
        ds.setMaxWait(Long.valueOf(getMaxWait()));
        ds.setMaxActive(Integer.valueOf(getMaxActive()));
        ds.setMinEvictableIdleTimeMillis(Long.valueOf(getMinEvictableIdleTimeMillis()));
        ds.setFilters("stat,wall");
        return dataSource;
    }

    @Bean(name = "activitiJdbcTemplate")
    public JdbcTemplate activitiJdbcTemplate() {
        return new JdbcTemplate(activitiDataSource());
    }

    @Bean(name = "apEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean activitiEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("activitiDataSource") DataSource barDataSource) {
        return builder.dataSource(activitiDataSource())
                .packages(PACKAGE+".domain")//这里需要修改
                .persistenceUnit(ProcessEngines.NAME_DEFAULT)
                //.persistenceUnit("dataModel")//这里需要修改
                .build();
    }

    @Bean(name = "activitiTransactionManager")
    public DataSourceTransactionManager activitiTransactionManager() {
        return new DataSourceTransactionManager(activitiDataSource());
    }

    @Bean(name = "apTransactionManager")
    public PlatformTransactionManager activitiTransactionManager(
            @Qualifier("apEntityManagerFactory") EntityManagerFactory dmEntityManagerFactory) {
        return new JpaTransactionManager(dmEntityManagerFactory);
    }

    @Bean(name = "activitiSqlSessionFactory")
    public SqlSessionFactory activitiSqlSessionFactory(@Qualifier("activitiDataSource") DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }
}


